package com.yanqu.road.server.gameplayer.module.activity.bowart;

import com.yanqu.road.entity.activity.bowart.BowArtJianBaRingInfo;
import com.yanqu.road.entity.activity.bowart.BowArtMingZhongScoreInfo;
import com.yanqu.road.entity.activity.bowart.BowArtUserData;
import com.yanqu.road.entity.activity.bowart.enums.eWindDirection;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.LogBaiYeGet;
import com.yanqu.road.entity.log.LogBowArtLaunch;
import com.yanqu.road.entity.log.LogBowArtPatronsSend;
import com.yanqu.road.entity.log.LogBowArtSmelt;
import com.yanqu.road.entity.player.UserBagItem;
import com.yanqu.road.entity.player.UserPatrons;
import com.yanqu.road.entity.task.args.UnionRiseRankArgs;
import com.yanqu.road.logic.bussiness.activity.BowArtBusiness;
import com.yanqu.road.pb.activity.BowArtProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.patrons.PatronsModule;
import com.yanqu.road.server.gameplayer.module.player.BagModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.bowart.BowArtMgr;
import com.yanqu.road.server.manger.activity.bowart.Coordinate;
import com.yanqu.road.server.manger.activity.bowart.TargetBehavior;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigDecimal;
import java.math.BigInteger;

public class BowArtModule extends GeneralModule {

    BowArtUserData userData;

    RandomHelper randomHelper = new RandomHelper();

    public BowArtModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        int activityId = BowArtMgr.getShowTimeActivityId();
        if (activityId != 0 && SystemOpenMgr.systemOpen(player, eSystemId.BowArtActivity.getValue())) {
            userData = BowArtBusiness.getUserData(player.getUserId(), activityId);
            if (userData == null) {
                initUserData();
            }
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return false;
    }

    @Override
    public boolean saveData() {
        if(userData != null){
            if(userData.isInsertOption()){
                BowArtBusiness.addBowArtUserData(userData);
            }else if(userData.isUpdateOption()){
                BowArtBusiness.updateBowArtUserData(userData);
            }
        }
        return true;
    }


    @Override
    public void afterLogin() {
        syncUserData();
    }

    public void initUserData() {
        int showTimeActivityId = BowArtMgr.getShowTimeActivityId();
        if(showTimeActivityId == 0){
            return;
        }
        if(userData == null || userData.getActivityId() != showTimeActivityId) {

            BowArtUserData tempUserData = new BowArtUserData();
            tempUserData.setActivityId(showTimeActivityId);
            tempUserData.setUserId(player.getUserId());
            tempUserData.setInsertOption();

            userData = tempUserData;
        }
    }

    public void syncUserData() {
        if(this.userData == null){
            return;
        }
        BowArtProto.BowArtUserDataSyncMsg.Builder syncMsg = BowArtProto.BowArtUserDataSyncMsg.newBuilder();
        BowArtProto.BowArtUserDataTemp.Builder dataBuilder = BowArtMgr.getUserDataBuilder(this.userData);
        syncMsg.setActivityId(BowArtMgr.getShowTimeActivityId());
        syncMsg.setUserData(dataBuilder);
        syncMsg.setSmeltOpenVal(BowArtMgr.BOW_ART_SMELT_OPEN_VALUE);
        player.sendPacket(Protocol.U_BOW_ART_ACTIVITY_SYNC_USER_DATA, syncMsg);
    }

    public void dailyReset() {

    }

    public void initSystem() {
        if(userData == null){
            initUserData();
            syncUserData();
        }
    }

    /**
     * 随机风力（固定1-10级别）
     */
    public int getRandomWindPower(){
        return randomHelper.next(1, 11);
    }

    /**
     * 随机风向
     */
    public int getRandomWindDirection(){
        return randomHelper.next(1, eWindDirection.values().length + 1);
    }

    public BowArtUserData getUserData() {
        return userData;
    }

    /**
     * 准备
     */
    public int prepare() {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_NO_FOUND;
        }
        BowArtProto.BowArPrepareRespMsg.Builder respMsg = BowArtProto.BowArPrepareRespMsg.newBuilder();
        respMsg.setRet(0);
        synchronized (userData){
            userData.setInTime(System.currentTimeMillis());
            if(userData.getCurTargetIndex() == -1){
                userData.setCurTargetIndex(0);
            }
            if(userData.getWindPower() == 0 || userData.getWindDirection() == 0){
                userData.setWindDirection(getRandomWindDirection());
                userData.setWindPower(getRandomWindPower());
            }
            TargetBehavior behavior = BowArtMgr.getTargetBehaviorList().get(userData.getCurTargetIndex());
            if(behavior == null){
                behavior = BowArtMgr.getTargetBehaviorList().get(0);
                userData.setCurTargetIndex(0);
            }
            int cycleTime = BowArtMgr.getBowArtMoveCycleTime().get(behavior.getTargetType());
            respMsg.setCycleTime(cycleTime);
            respMsg.setOffsetDistance(BowArtMgr.getBowArtMaxOffsetDistance().get(behavior.getDistanceIdx()));
            respMsg.setCurTargetDistanceIdx(behavior.getDistanceIdx());
            respMsg.setCurTargetType(behavior.getTargetType());
        }
        respMsg.setWindDirection(userData.getWindDirection());
        respMsg.setWindPower(userData.getWindPower());
        player.sendPacket(Protocol.U_BOW_ART_ACTIVITY_IN_PREPARE, respMsg);
        return 0;
    }

    /**
     * 射箭
     */
    public int launchArrow(int goodsId, int timeGap, Coordinate hitPoint) {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_NO_FOUND;
        }
        if(userData.getCurTargetIndex() < 0 || userData.getCurTargetIndex() > BowArtMgr.getTargetBehaviorList().size() -1){
            return -1;
        }
        Property consume = PropertyHelper.parseStringToProperty(goodsId + "=1");
        if(!player.getModule(CurrencyModule.class).currencyIsEnough(consume)){
            return GameErrorCode.E_BOW_ART_ACTIVITY_GOODS_NO_ENOUGH;
        }
        if(userData.getPatronsId() == 0){
            return GameErrorCode.E_BOW_ART_ACTIVITY_NO_SEND_PATRONS;
        }
        //时间校验
        //后端gap
        int backendGap = (int)(System.currentTimeMillis() - userData.getInTime());
        //网络传输消耗或延时超过3500毫秒
        if(backendGap - timeGap > 3500){
            return GameErrorCode.E_BOW_ART_ACTIVITY_LAUNCH_FAILS;
        }

        //当前箭靶
        TargetBehavior targetBehavior = BowArtMgr.getTargetBehaviorList().get(userData.getCurTargetIndex());
        int cycleTime = BowArtMgr.getBowArtMoveCycleTime().get(targetBehavior.getTargetType());
        Coordinate bullsEye = targetBehavior.getBullsEye2(timeGap, cycleTime);
        log.info("bullsEye:({},{})", bullsEye.getX(), bullsEye.getY());
        //受风力影响
        Coordinate finalPoint = calFinalPointByWin(hitPoint, BowArtMgr.getMaxOffsetPixel(targetBehavior.getDistanceIdx()), userData.getWindDirection(), userData.getWindPower());
        //log.info("finalPoint:({},{})", finalPoint.getX(), finalPoint.getY());
        //两个圆心的距离
        double eyeDistance = BigDecimal.valueOf(Math.sqrt(Math.pow(bullsEye.getX() - finalPoint.getX(), 2) + Math.pow(bullsEye.getY() - finalPoint.getY(), 2)))
                .setScale(5, BigDecimal.ROUND_UP).doubleValue();
        //log.info("eyeDistance : {}", eyeDistance);
        //环数
        BowArtJianBaRingInfo ringConfigInfo = BowArtMgr.getJianBaRingConfig(eyeDistance);
        long score = 0;
        int exp = 0;
        //连续命中成就
        BowArtMingZhongScoreInfo mingZhongScoreInfo = null;
        synchronized (userData) {
            if(!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.BowArt, eLogMoneyType.BowArtActivityUseGoods)){
                return GameErrorCode.E_BOW_ART_ACTIVITY_GOODS_NO_ENOUGH;
            }
            LogBowArtLaunch launchLog = new LogBowArtLaunch(player.getUserId(), BowArtMgr.getShowTimeActivityId(), goodsId, 0, targetBehavior.getTargetType());
            GoodsInfo goodsInfo = GoodsMgr.getGoodsById(goodsId);
            if (ringConfigInfo != null) {
                if(goodsInfo != null){
                    //基础分
                    score += goodsInfo.getParamList().get(0).longValue();
                }
                //命中环数分数
                score += ringConfigInfo.getIntegral() * BowArtMgr.getDifficulty(targetBehavior.getTargetType());
                //(基础分 + 命中分 * 难度系数) * 箭矢系数
                score = getScore(score, goodsInfo.getParamList().get(2).longValue());

                //是否圆心
                if (ringConfigInfo.getRadius().get(0) == 0 && ringConfigInfo.getRing() == 10) {
                    userData.setContiRings(userData.getContiRings() + 1);
                    mingZhongScoreInfo = BowArtMgr.getBowArtMingZhongScoreInfo(userData.getContiRings());
                }else {
                    userData.setContiRings(0);
                }
                if(mingZhongScoreInfo != null){
                    //连续命中附加分
                    score += mingZhongScoreInfo.getIntegral();
                }
                launchLog.setRings(ringConfigInfo.getRing());
            }else {
                userData.setContiRings(0);
                //基础分 * 箭矢系数
                if(goodsInfo != null) {
                    score += getScore(goodsInfo.getParamList().get(0).longValue(), goodsInfo.getParamList().get(2).longValue());
                }
            }
            //命中日志
            launchLog.setScore(score);
            AutoLogMgr.add(launchLog);
            exp = BigDecimal.valueOf(score).multiply(BigDecimal.valueOf(BowArtMgr.BOW_ART_BAIYE_RATIO)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_DOWN).intValue();
            userData.setTotalScore(userData.getTotalScore() + score);

            //道具积分
            player.getModule(CurrencyModule.class).addCurrency(BowArtMgr.BOW_ART_SCORE_GOODS_ID + "=" + score, eLogMoneyType.BowArt, eLogMoneyType.BowArtActivityGoodsReward);

            //排行榜
            player.notifyListener(eGamePlayerEventType.BowArtActivityScoreRank.getValue(), userData.getTotalScore());
            player.notifyListener(eGamePlayerEventType.BowArtActivityScoreCrossRank.getValue(), userData.getTotalScore());
//            player.notifyListener(eGamePlayerEventType.BowArtActivityUnionScoreRank.getValue(), new UnionRiseRankArgs(UnionRiseRankArgs.NOTIFY_TYPE_NORMAL, BigInteger.valueOf(userData.getTotalScore()), player.getUserInfo().getUnionUid()));
//            player.notifyListener(eGamePlayerEventType.BowArtActivityUnionScoreCrossRank.getValue(), new UnionRiseRankArgs(UnionRiseRankArgs.NOTIFY_TYPE_NORMAL, BigInteger.valueOf(userData.getTotalScore()), player.getUserInfo().getUnionUid()));

            //随机下一场数据
            userData.setWindPower(getRandomWindPower());
            userData.setWindDirection(getRandomWindDirection());
            userData.setCurTargetIndex(BowArtMgr.getNextTargetBehavior(userData.getCurTargetIndex()));
        }
        if(exp > 0){
            UserPatrons userPatrons = player.getModule(PatronsModule.class).getUserPatrons(userData.getPatronsId());
            if(userPatrons != null){
                userPatrons.setBaiYeExp(userPatrons.getBaiYeExp() + exp);
                player.getModule(PatronsModule.class).syncPatronsData(userPatrons);
            }
            //百业经验日志
            LogBaiYeGet logBaiYeGet = new LogBaiYeGet(player.getUserId(), BowArtMgr.getShowTimeActivityId(), userData.getPatronsId(), exp, System.currentTimeMillis());
            LogMgr.addLogBaiYeGet(logBaiYeGet);
        }
        //结果返回
        BowArtProto.BowArtLaunchArrowRespMsg.Builder respMsg = BowArtProto.BowArtLaunchArrowRespMsg.newBuilder();
        respMsg.setRet(0);
        if(ringConfigInfo != null) {
            respMsg.setHitRing(ringConfigInfo.getRing());
        }else {
            respMsg.setHitRing(0);
        }
        respMsg.setScore((int)score);
        respMsg.setExp(exp);
        BowArtProto.BowArtPointTemp.Builder pointBuilder = BowArtProto.BowArtPointTemp.newBuilder();
        pointBuilder.setX(finalPoint.getX());
        pointBuilder.setY(finalPoint.getY());
        respMsg.setHitPoint(pointBuilder);
        if(mingZhongScoreInfo != null){
            respMsg.setEyeScore(BowArtMgr.getMingZhongScoreBuilder(mingZhongScoreInfo));
        }
        respMsg.setUserData(BowArtMgr.getUserDataBuilder(userData));
        player.sendPacket(Protocol.U_BOW_ART_ACTIVITY_LAUNCH_ARROW, respMsg);
        return 0;
    }

    /**
     * 分数 * 箭矢系数
     */
    private long getScore(long score, long ratio) {
        return BigDecimal.valueOf(score).multiply(BigDecimal.valueOf(ratio).divide(
                BigDecimal.valueOf(1000), 2, BigDecimal.ROUND_UP)).longValue();
    }

    /**
     * 受风力影响
     * windPower/10 是风力影响系数
     */
    private Coordinate calFinalPointByWin(Coordinate hitPoint, int maxDistanceOffset, int windDirectionId, int windPower) {
        double x = hitPoint.getX();
        double y = hitPoint.getY();
        eWindDirection windDirection = eWindDirection.forValue(windDirectionId);
        //double power = (double)(maxDistanceOffset * windPower) / 10;
        //double len = power / Math.sqrt(Math.pow(windDirection.getOffsetX(), 2) + Math.pow(windDirection.getOffsetY(), 2));
        double len = BigDecimal.valueOf(maxDistanceOffset * windPower).divide(BigDecimal.valueOf(10), 5, BigDecimal.ROUND_UP).divide(BigDecimal.valueOf(
                Math.sqrt(Math.pow(windDirection.getOffsetX(), 2) + Math.pow(windDirection.getOffsetY(), 2))), 5, BigDecimal.ROUND_UP).doubleValue();
        //log.info("len : {}", len);
        x += len * windDirection.getOffsetX();
        y += len * windDirection.getOffsetY();
        return new Coordinate(x, y);
    }

    /**
     * 派遣门客
     * @param patronsId
     * @return
     */
    public int dispatchPatrons(int patronsId) {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_NO_FOUND;
        }
        userData.setPatronsId(patronsId);
        //日志
        AutoLogMgr.add(new LogBowArtPatronsSend(player.getUserId(), BowArtMgr.getShowTimeActivityId(), patronsId));
        BowArtProto.BowArtDispatchPatronsRespMsg.Builder respMsg = BowArtProto.BowArtDispatchPatronsRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setPatronsId(patronsId);
        player.sendPacket(Protocol.U_BOW_ART_ACTIVITY_DISPATCH_PATRONS, respMsg);
        return 0;
    }

    private BowArtProto.BowArtSmeltRespMsg.Builder buildSmeltResp(long[] result, int[] items, Property property) {
        BowArtProto.BowArtSmeltRespMsg.Builder respMsg = BowArtProto.BowArtSmeltRespMsg.newBuilder();
        respMsg.setRet(0);
        for(int i = 0; i < items.length; i++){
            property.setGood(items[i], BigInteger.valueOf(result[i]));
        }
        respMsg.setReward(PropertyHelper.parsePropertyToString(property));
        return  respMsg;
    }

    /**
     * 熔炼预览
     */
    public int preSmelt() {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_NO_FOUND;
        }
        if(userData.getTotalScore() < BowArtMgr.BOW_ART_SMELT_OPEN_VALUE){
            return GameErrorCode.E_BOW_ART_ACTIVITY_SMELT_SCORE_NO_ENOUGH;
        }
        int[] items = getItems();
        //结果
        long[] result = new long[5];
        boolean change = calSmelt(result, items);
        if(!change){
            result = new long[5];
        }
        Property property = new Property();
        BowArtProto.BowArtSmeltRespMsg.Builder respMsg = buildSmeltResp(result, items, property);
        player.sendPacket(Protocol.U_BOW_ART_ACTIVITY_SMELT_PRE, respMsg);
        return 0;
    }

    /**
     * 熔炼
     */
    public int smelt() {
        if(userData == null){
            return GameErrorCode.E_ACTIVITY_NO_FOUND;
        }
        if(userData.getTotalScore() < BowArtMgr.BOW_ART_SMELT_OPEN_VALUE){
            return GameErrorCode.E_BOW_ART_ACTIVITY_SMELT_SCORE_NO_ENOUGH;
        }
        int[] items = getItems();
        //结果
        long[] result = new long[5];
        synchronized (userData){
            boolean change = calSmelt(result, items);
            CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
            if(change){
                long time = System.currentTimeMillis();
                if(result[0] > 0) {
                    currencyModule.addCurrency(items[0] + "=" + result[0], eLogMoneyType.BowArt, eLogMoneyType.BowArtActivitySmeltGoods);
                    //熔炼日志
                    AutoLogMgr.add(new LogBowArtSmelt(player.getUserId(), BowArtMgr.getShowTimeActivityId(), items[0], (int) result[0]));
                }
                //比较差异
                for(int i = 1; i < items.length; i++) {
                    long oldNum = getNumByGoodsId(items[i]);
                    if(oldNum <= 0 && result[i] <= 0){
                        continue;
                    }
                    if(result[i] > oldNum){
                        currencyModule.addCurrency(items[i] + "=" + (result[i] - oldNum), eLogMoneyType.BowArt, eLogMoneyType.BowArtActivitySmeltGoods);
                    }else if(oldNum > result[i]){
                        currencyModule.removeCurrency(PropertyHelper.parseStringToProperty(items[i] + "=" + (oldNum - result[i])), eLogMoneyType.BowArt, eLogMoneyType.BowArtActivitySmeltGoods);
                    }
                    //熔炼日志
                    AutoLogMgr.add(new LogBowArtSmelt(player.getUserId(), BowArtMgr.getShowTimeActivityId(), items[i], (int) (result[i] - oldNum)));
                }
            }else {
                result = new long[5];
            }
            Property property = new Property();
            BowArtProto.BowArtSmeltRespMsg.Builder respMsg = buildSmeltResp(result, items, property);
            player.sendPacket(Protocol.U_BOW_ART_ACTIVITY_SMELT, respMsg);
        }
        return 0;
    }

    /**
     * 熔炼计算
     * @param result 道具数量
     * @param items  道具列表（高积分至低积分）
     */
    private boolean calSmelt(long[] result, int[] items) {
        boolean change = false;
        long[] temp = new long[result.length];
        //初始积分配置
        long[] scoreConfig = getScoreConfigByGoodsId(items);
        for(int i = 1; i < items.length; i++){
            //初始道具数量
            result[i] = getNumByGoodsId(items[i]);
            temp[i] = result[i];
        }
        //校验配置是否是整数倍
        for(int j = 0; j < scoreConfig.length; j++){
            if(scoreConfig[j] % scoreConfig[scoreConfig.length -1] != 0){
                return false;
            }
        }
        smelt(scoreConfig, result, 0);
        for(int i = 0; i < result.length; i++){
            if(result[i] != temp[i]){
                change = true;
                break;
            }
        }
        for(int j = 0; j < result.length; j++){
            if(result[j] < 0) {
                //result如果有负值，说明计算有误
                change = false;  //不让熔炼
                break;
            }
        }

        return change;
    }

    /**
     * 获取背包道具数量
     */
    private long getNumByGoodsId(int goodsId){
        UserBagItem userBagItem = player.getModule(BagModule.class).getUserBagItem(goodsId);
        if(userBagItem != null && userBagItem.getNum() > 0){
            return userBagItem.getNum();
        }
        return 0l;
    }

    /**
     * 获取道具对应配置的积分
     */
    private long[] getScoreConfigByGoodsId(int[] items) {
        long[] score = new long[items.length];
        for(int i = 0; i < items.length; i++) {
            GoodsInfo goodsInfo = GoodsMgr.getGoodsById(items[i]);
            if (goodsInfo != null) {
                score[i] = goodsInfo.getParamList().get(2).longValue();
            }
        }
        return score;
    }

    /**
     * 待熔炼的道具列表（高积分至低积分，积分都可以被最低积分整除）
     */
    private int[] getItems() {
        int[] items = new int[5];
        items[0] = BowArtMgr.BOW_ART_XUAN_YUAN_JIAN_ID;
        items[1] = BowArtMgr.BOW_ART_JIANG_JUN_JIAN_ID;
        items[2] = BowArtMgr.BOW_ART_LIU_YE_JIAN_ID;
        items[3] = BowArtMgr.BOW_ART_TIE_JIAN_ID;
        items[4] = BowArtMgr.BOW_ART_MU_JIAN_ID;
        return items;
    }

    /**
     * 熔炼
     * @param score  所有道具分数（0...n 为高积分至低积分）
     * @param result  所有道具数量
     * @param start 开始熔炼位置（0...n)
     */
    private void smelt(long[] score, long[] result,int start){
        long allScore = 0;
        for(int i = start + 1; i < result.length; i++){
            allScore += score[i] * result[i];
        }
        if(allScore == 0){
            return;
        }
        long max = allScore / score[start];
        result[start] = result[start] + max;
        long minScore = score[score.length - 1];
        long allBs = max * score[start] / minScore;
        if(max > 0) {
            for (int j = start + 1; j < score.length; j++) {
                if (allBs == 0) {
                    break;
                }
                long tempBs = score[j] * result[j] / minScore;
                long perBs = score[j] / minScore;
                if(allBs < tempBs){
                    tempBs = allBs;
                    if(allBs % perBs != 0){
                        //多扣，化为最低等级
                        result[score.length - 1] += perBs - (allBs % perBs);
                        result[j] -= (tempBs / perBs + 1) ;
                    }else {
                        result[j] -= tempBs / perBs;
                    }
                }else {
                    result[j] -= tempBs / perBs;
                }
                allBs -= tempBs;
            }
        }
        if(start < score.length - 1){
            smelt(score, result, start + 1);
        }
    }


}
